/**
 * System:      oshys
 * Model:       log
 * Licence:     GNU General Public License v3
 * Author:      sunwl
 * Date:        2010/02/19
 */
package org.oshys.util.logging;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;

import static org.oshys.util.logging.ConfigProvider.getResource;
import static org.oshys.util.logging.ConfigProvider.getIntResource;
/**
 * 输出Log消息到文件的类。<br>
 * 该类在当前的消息文件大小达到一定程度以后，将根据配置文件中的logging.file项更改文件名，并重新输出到一个新的文件中。
 * 该类相关的几个配置项：<br>
 * logging.file：输出消息的文件名，配置中的%index将被替换成0、1、2、3等<br>
 * logging.file.size：输出消息的文件的大小上限，单位为KB，默认为10240KB
 * logging.file.keepno：保存输出消息的文件的个数，默认为1个
 * logging.file.level：输出到文件中的消息的级别
 * 
 * @author sunwl
 *
 */
public class RotateFileAppender extends StreamAppender {
    //当前文件的大小
    private transient long size = 0;
    //消息文件名称
    private String filepathFormat = null;
    //保存消息文件的个数
    private int fileKeepNo = 0;
    //单个消息文件的 最大体积
    private int maxSize = 0;
    //保存消息文件的数组
    private File[] logFiles = null;
    
    /**
     * 构造方法<br>
     * 读取配置信息并初始化各内部对象。<br>
     * 默认情况下，设置格式化器为SimpleFormatter
     */
    protected RotateFileAppender () {
    	this.config();
    	this.init();
    	this.formatter = new SimpleFormatter();
    }
    
    /**
     * 构造方法<br>
     * 读取配置信息并初始化各内部对象。<br>
     * 设置格式化器。
     */
    
    protected RotateFileAppender(IFormatter formatter){
    	this.config();
    	this.init();
    	this.formatter = formatter;
    }
    
    public synchronized long getSize(){
    	return this.size;
    }
    
    public synchronized long getMaxSize(){
    	return this.maxSize;
    }
    
    /**
     * 输出消息到文件。<br>
     * 当文件到达设定的上限时，将文件改名并把消息输出到一个新文件中。<br>
     * 注意：该方法不分割一个独立的Log消息实体。<br>
     * 比如：当前设定文件大小上限为10240字节，当前文件大小为10000字节，待输出的消息大小为300字节，<br>
     * 那么，该消息将输出到一个新的文件中，而之前的文件并不会达到10240字节。
     */
    public synchronized void append(LogMessage logMessage) {
    	if(!toAppend(logMessage)){
    		return;
    	}
    	
    	String msg = this.formatter.format(logMessage);
    	try {
			if (this.getSize() + msg.length() > this.getMaxSize()) {
				super.flushAndClose();
				for (int i = logFiles.length - 2; i >= 0; i--) {
					if(logFiles[i].exists()){
						if (logFiles[i + 1].exists()) {
							logFiles[i + 1].delete();
						}
						logFiles[i].renameTo(logFiles[i + 1]);
					}
				}

				writer = new FileWriter(logFiles[0]);
				this.size = 0;
			}
			writer.write(msg);
			writer.flush();
			this.size += msg.length();

		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    
    private void config() {
		filepathFormat = getResource("logging.file", "\\log.log");
		fileKeepNo = getIntResource("logging.file.keepno", 1);
		if(fileKeepNo <= 0)fileKeepNo = 1;
		
		maxSize = getIntResource("logging.file.size", 10240);
		if(maxSize <= 0 )maxSize = 10240;
		else maxSize = 1024 * maxSize;
		
		logFiles = new File[fileKeepNo];
	}
    
    private void init(){
    	for(int i = 0;i < logFiles.length;i++){
    		String filepath = filepathFormat.replaceAll("%index", String.valueOf(i));
    		logFiles[i] = new File(filepath);
    	}
    	if(this.logFiles[0].exists()){
    		this.size = this.logFiles[0].length();
    	}
    	try {
			this.writer = new FileWriter(this.logFiles[0], true);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    
}


